package com.toomoss.USB2XXX;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;

public interface USB2CAN extends Library {
	USB2CAN INSTANCE  = (USB2CAN)Native.loadLibrary("USB2XXX",USB2CAN.class); 
	
    //0.函数返回错误代码定义
    public static int CAN_SUCCESS           =(0);   //函数执行成功
    public static int CAN_ERR_NOT_SUPPORT   =(-1);  //适配器不支持该函数
    public static int CAN_ERR_USB_WRITE_FAIL=(-2);  //USB写数据失败
    public static int CAN_ERR_USB_READ_FAIL =(-3);  //USB读数据失败
    public static int CAN_ERR_CMD_FAIL      =(-4);  //命令执行失败
    public static int CAN_BL_ERR_CONFIG		=(-20); //配置设备错误
    public static int CAN_BL_ERR_SEND		=(-21); //发送数据出错
    public static int CAN_BL_ERR_TIME_OUT	=(-22); //超时错误
    public static int CAN_BL_ERR_CMD		=(-23); //执行命令失败
    public static int CAN_BOOT_ERR_CONFIG   =(-30); //配置设备错误
    public static int CAN_BOOT_ERR_SEND     =(-31); //发送数据出错
    public static int CAN_BOOT_ERR_TIME_OUT =(-32); //超时错误
    public static int CAN_BOOT_ERR_CMD      =(-33); //执行命令失败
    public static int CAN_BOOT_ERR_BAUD     =(-34); //波特率参数自动获取失败
    public static int CAN_BOOT_ERR_BUFFER   =(-35); //从设备返回接收数据缓冲区大小为0
    public static int CAN_BL_BOOT   =  0x55555555;
    public static int CAN_BL_APP    =  0xAAAAAAAA;
    //1.CAN信息帧的数据类型定义
	public class CAN_MSG  extends Structure{
	    public static class ByReference extends CAN_MSG implements Structure.ByReference {}  
	    public static class ByValue extends CAN_MSG implements Structure.ByValue {}

		@Override
		protected List getFieldOrder() {
			// TODO Auto-generated method stub
			return Arrays.asList(new String[]{"ID","TimeStamp","RemoteFlag","ExternFlag","DataLen","Data","TimeStampHigh"});
		}

        public int  ID;			//报文ID。
        public int  TimeStamp;	//接收到信息帧时的时间标识，从CAN 控制器初始化开始计时。单位为100us
        public byte RemoteFlag;	//bit[0]-是否是远程帧,bit[6..5]-当前帧通道号，bit[7]-发送帧标志
        public byte	ExternFlag;	//是否是扩展帧
        public byte	DataLen;	//数据长度(<=8)，即Data 的长度。
        public byte[]	Data = new byte[8];	//报文的数据。
		public byte	TimeStampHigh;//时间戳高位
    }

    //2.初始化CAN的数据类型定义
	public class CAN_INIT_CONFIG  extends Structure{
	    public static class ByReference extends CAN_INIT_CONFIG implements Structure.ByReference {}  
	    public static class ByValue extends CAN_INIT_CONFIG implements Structure.ByValue {}  
	  
		@Override
		protected List getFieldOrder() {
			// TODO Auto-generated method stub
			return Arrays.asList(new String[]{"CAN_BRP","CAN_SJW","CAN_BS1","CAN_BS2","CAN_Mode","CAN_ABOM","CAN_NART","CAN_RFLM","CAN_TXFP"});
		}
        //CAN波特率 = 100MHz/(CAN_BRP)/(CAN_SJW+CAN_BS1+CAN_BS2)
        public int	CAN_BRP;	//取值范围1~1024
        public byte	CAN_SJW;	//取值范围1~4
        public byte	CAN_BS1;	//取值范围1~16
        public byte	CAN_BS2;	//取值范围1~8
        public byte	CAN_Mode;	//CAN工作模式，0-正常模式，1-环回模式，2-静默模式，3-静默环回模式，bit7为1则接入适配器内部终端电阻，否则不接入
        public byte	CAN_ABOM;	//自动离线管理，0-禁止，1-使能
        public byte	CAN_NART;	//报文重发管理，0-使能报文重传，1-禁止报文重传
        public byte	CAN_RFLM;	//FIFO锁定管理，0-新报文覆盖旧报文，1-丢弃新报文
        public byte	CAN_TXFP;	//发送优先级管理，0-标识符决定，1-发送请求顺序决定
    }


    //3.CAN 滤波器设置数据类型定义
	public class CAN_FILTER_CONFIG  extends Structure{
	    public static class ByReference extends CAN_FILTER_CONFIG implements Structure.ByReference {}  
	    public static class ByValue extends CAN_FILTER_CONFIG implements Structure.ByValue {}  
	  
		@Override
		protected List getFieldOrder() {
			// TODO Auto-generated method stub
			return Arrays.asList(new String[]{"Enable","FilterIndex","FilterMode","ExtFrame","ID_Std_Ext","ID_IDE","ID_RTR","MASK_Std_Ext","MASK_IDE","MASK_RTR"});
		}
        public byte	Enable;			//使能该过滤器，1-使能，0-禁止
        public byte	FilterIndex;	//过滤器索引号，取值范围为0到13
        public byte	FilterMode;		//过滤器模式，0-屏蔽位模式，1-标识符列表模式
        public byte	ExtFrame;		//过滤的帧类型标志，为1 代表要过滤的为扩展帧，为0 代表要过滤的为标准帧。
        public int	ID_Std_Ext;		//验收码ID
        public int	ID_IDE;			//验收码IDE
        public int	ID_RTR;			//验收码RTR
        public int	MASK_Std_Ext;	//屏蔽码ID，该项只有在过滤器模式为屏蔽位模式时有用
        public int	MASK_IDE;		//屏蔽码IDE，该项只有在过滤器模式为屏蔽位模式时有用
        public int	MASK_RTR;		//屏蔽码RTR，该项只有在过滤器模式为屏蔽位模式时有用
    }
    //4.CAN总线状态数据类型定义
	public class CAN_STATUS  extends Structure{
	    public static class ByReference extends CAN_STATUS implements Structure.ByReference {}  
	    public static class ByValue extends CAN_STATUS implements Structure.ByValue {}  
	  
		@Override
		protected List getFieldOrder() {
			// TODO Auto-generated method stub
			return Arrays.asList(new String[]{"TSR","ESR","RECounter","TECounter","LECode"});
		}
        public int     TSR;
        public int     ESR;
        public byte    RECounter;	//CAN 控制器接收错误寄存器。
        public byte    TECounter;	//CAN 控制器发送错误寄存器。
        public byte    LECode;     //最后的错误代码
    }
    //5.定义CAN Bootloader命令列表
	public class CBL_CMD_LIST  extends Structure{
	    public static class ByReference extends CBL_CMD_LIST implements Structure.ByReference {}  
	    public static class ByValue extends CBL_CMD_LIST implements Structure.ByValue {}  
	  
		@Override
		protected List getFieldOrder() {
			// TODO Auto-generated method stub
			return Arrays.asList(new String[]{"Erase","WriteInfo","Write","Check","SetBaudRate","Excute","CmdSuccess","CmdFaild"});
		}
        //Bootloader相关命令
        public byte   Erase;            //擦出APP储存扇区数据
        public byte   WriteInfo;        //设置多字节写数据相关参数（写起始地址，数据量）
        public byte   Write;            //以多字节形式写数据
        public byte   Check;            //检测节点是否在线，同时返回固件信息
        public byte   SetBaudRate;    //设置节点波特率
        public byte   Excute;            //执行固件
        //节点返回状态
        public byte   CmdSuccess;        //命令执行成功
        public byte   CmdFaild;        //命令执行失败
    }
	//USB2CAN函数定义
	/**
	 * @brief  通过波特率值获取具体的波特率参数，调用该函数后还需要调用 @ref CAN_Init 函数才能设置设备波特率值
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param[out]  pCanConfig CAN初始化结构体，用于存储波特率参数
	 * @param  SpeedBps CAN波特率值，单位为bps，比如500K波特率，则传入500000
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int CAN_GetCANSpeedArg(int DevHandle,CAN_INIT_CONFIG pCanConfig, int SpeedBps);
	/**
	 * @brief  初始化CAN总线，使用CAN功能时必须调用
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pCanConfig CAN初始化相关参数，具体可以参考 @ref CAN_INIT_CONFIG
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_Init(int DevHandle, byte CANIndex, CAN_INIT_CONFIG pCanConfig);

	/**
	 * @brief  配置CAN过滤器，通过配置过滤器可以只接收特定ID帧，或者指定ID范围内的帧
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pFilterConfig CAN过滤器参数，具体可以参考 @ref CAN_FILTER_CONFIG
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_Filter_Init(int DevHandle, byte CANIndex, CAN_FILTER_CONFIG pFilterConfig);
	/**
	 * @brief  启动CAN消息自动读取功能，调用后会在后台自动读取CAN消息并将消息存储在上位机数据缓冲区中，调用该函数可以防止数据丢失
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_StartGetMsg(int DevHandle, byte CANIndex);
	/**
	 * @brief  停止自动接收CAN消息，停止后适配器收到CAN消息后会将消息缓存到适配器内部数据缓冲区，若长时间不去读取数据，则先接收到的数据会被丢失
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int CAN_StopGetMsg(int DevHandle, byte CANIndex);
	/**
	 * @brief  发送CAN消息，消息发送完毕后该函数才会返回，发送期间会完全占用USB总线
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pCanSendMsg CAN消息指针
	 * @param  SendMsgNum 待发送的消息帧数
	 * @return 函数执行状态
	 * @retval =0 CAN消息未发送成功
	 * @retval >0 成功发送消息帧数
	 * @retval <0 函数调用失败
	 */
	int  CAN_SendMsg(int DevHandle, byte CANIndex, CAN_MSG[] pCanSendMsg,int SendMsgNum);
	/**
	 * @brief  同步模式发送CAN消息，发送消息的时候不会完全占用USB总线
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pCanSendMsg CAN消息指针
	 * @param  SendMsgNum 待发送的消息帧数
	 * @return 函数执行状态
	 * @retval =0 CAN消息未发送成功
	 * @retval >0 成功发送消息帧数
	 * @retval <0 函数调用失败
	 */
	int CAN_SendMsgSynch(int DevHandle, byte CANIndex, CAN_MSG[] pCanSendMsg, int SendMsgNum);
	/**
	 * @brief  定时间隔模式发送CAN消息，发送消息的时候会完全占用USB总线，函数是阻塞的，同时会把发送帧放到接收数据缓冲区里面
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pCanSendMsg CAN消息指针
	 * @param  SendMsgNum 待发送的消息帧数
	 * @return 函数执行状态
	 * @retval =0 CAN消息未发送成功
	 * @retval >0 成功发送消息帧数
	 * @retval <0 函数调用失败
	 */
	int CAN_SendMsgWithTime(int DevHandle, byte CANIndex, CAN_MSG[] pCanSendMsg, int SendMsgNum);
	/**
	 * @brief  读取接收到的CAN消息，若调用了 @ref CAN_StartGetMsg 函数，则从上位机缓冲区获取数据，否则从适配器内部获取数据
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[out]  pCanGetMsg 存储CAN消息数据缓冲区指针，调用该函数会返回缓冲区中所有数据，所以该缓冲区要设置大一点，以免缓冲区溢出，导致程序异常
	 * @return 函数执行状态
	 * @retval =0 未读取到CAN消息
	 * @retval >0 成功读取到的消息帧数
	 * @retval <0 函数调用失败
	 */
	int  CAN_GetMsg(int DevHandle, byte CANIndex, CAN_MSG[] pCanGetMsg);
	/**
	 * @brief  读取接收到的CAN消息
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[out]  pCanGetMsg 存储CAN消息数据缓冲区指针
	 * @param  BufferSize 数据缓冲区能存储CAN消息帧数，也就是数据缓冲区容量大小
	 * @return 函数执行状态
	 * @retval =0 未读取到CAN消息
	 * @retval >0 成功读取到的消息帧数
	 * @retval <0 函数调用失败
	 */
	int  CAN_GetMsgWithSize(int DevHandle, byte CANIndex, CAN_MSG[] pCanGetMsg,int BufferSize);
	/**
	 * @brief  清空CAN接收数据缓冲区
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int CAN_ClearMsg(int DevHandle, byte CANIndex);
	/**
	 * @brief  获取CAN总线状态信息
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[out]  pCANStatus CAN总线状态结构体指针，具体参考 @ref CAN_STATUS
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_GetStatus(int DevHandle, byte CANIndex, CAN_STATUS pCANStatus);
	/**
	 * @brief  设置CAN调度表数据，调度表模式发送数据可以精确控制帧之间的间隔时间，启动调度表后适配器可以自动发送调度表里面数据
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pCanMsgTab CAN调度表列表指针
	 * @param[in]  pMsgNum 调度表列表中每个调度表包含消息帧数
	 * @param[in]  pSendTimes 每个调度表里面帧发送次数，若为0xFFFF，则循环发送，通过调用 @ref CAN_StopSchedule 函数停止发送
	 * @param  MsgTabNum 调度表数
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_SetSchedule(int DevHandle, byte CANIndex, CAN_MSG[] pCanMsgTab,byte[] pMsgNum,short[] pSendTimes,byte MsgTabNum);
	/**
	 * @brief  启动CAN调度表
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  MsgTabIndex CAN调度表索引号
	 * @param  TimePrecMs 调度表时间精度，比如调度表里面最小帧周期为10ms，那么就建议设置为10
	 * @param  OrderSend 该调度表里面帧发送模式，0-并行发送，1-顺序发送
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_StartSchedule(int DevHandle, byte CANIndex, byte MsgTabIndex,byte TimePrecMs,byte OrderSend);
	/**
	 * @brief  更新调度表
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  MsgTabIndex CAN调度表索引号
	 * @param  MsgIndex 开始更新帧起始索引，若起始索引大于调度表帧数，则将帧添加到调度表后面
	 * @param[in]  pCanMsg 需要更新的CAN帧指针
	 * @param  MsgNum pCanMsgTab里面包含的有效帧数
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int CAN_UpdateSchedule(int DevHandle, byte CANIndex, byte MsgTabIndex, byte MsgIndex, CAN_MSG[] pCanMsg, byte MsgNum);
	/**
	 * @brief  停止执行CAN调度表
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_StopSchedule(int DevHandle, byte CANIndex);
	/**
	 * @brief  停止CAN总线，调用该函数后，适配器CAN节点将从CAN总线上断开，且无法正常应答其他节点发送的数据
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int CAN_Stop(int DevHandle, byte CANIndex);

	/**
	 * @brief  获取消息发送耗时时间，该值为理论值，实际值可能会大一些
	 * @param[in]  pMsg CAN消息指针
	 * @param  SpeedBps 总线波特率，单位为Hz
	 * @return 该帧发送耗时时间
	 * @retval 发送该帧耗时时间，单位为us
	 */
	int CAN_GetMsgSendTimeUs(CAN_MSG pMsg, int SpeedBps);
	//旧版本CAN Bootloader接口函数
	/**
	 * @brief  CAN BOOT初始化
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param[in]  pInitConfig 初始化结构体指针
	 * @param[in]  pCmdList 命令列表指针
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_Init(int DevHandle,int CANIndex,CAN_INIT_CONFIG pInitConfig,CBL_CMD_LIST pCmdList);
	/**
	 * @brief  节点在线状态检测
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  NodeAddr 节点地址
	 * @param[out]  pVersion 固件版本号输出
	 * @param[out]  pType 固件类型输出
	 * @param  TimeOut 超时时间，单位为毫秒
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_NodeCheck(int DevHandle,int CANIndex,short NodeAddr,int[] pVersion,int[] pType,int TimeOut);
	/**
	 * @brief  擦出用户区数据
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  NodeAddr 节点地址
	 * @param  FlashSize 待擦出的数据长度，单位为字节
	 * @param  TimeOut 超时时间，单位为毫秒
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_Erase(int DevHandle,int CANIndex,short NodeAddr,int FlashSize,int TimeOut);
	/**
	 * @brief  写数据到应用程序存储区
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  NodeAddr 节点地址
	 * @param  AddrOffset 数据写入起始地址
	 * @param[in]  pData 待写入的数据指针
	 * @param  DataNum 待写入数据字节数
	 * @param  TimeOut 超时时间，单位为毫秒
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_Write(int DevHandle,int CANIndex,short NodeAddr,int AddrOffset,byte[] pData,int DataNum,int TimeOut);
	/**
	 * @brief  执行程序
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  NodeAddr 节点地址
	 * @param  Type 固件类型
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_Excute(int DevHandle,int CANIndex,short NodeAddr,int Type);
	/**
	 * @brief  设置节点波特率
	 * @param  DevHandle 设备号，通过调用 @ref USB_ScanDevice 获取
	 * @param  CANIndex CAN通道号，0-CAN1，1-CAN2
	 * @param  NodeAddr 节点地址
	 * @param[in]  pInitConfig 初始化结构体指针
	 * @param  NewBaudRate 新波特率值，单位为bps
	 * @param  TimeOut 超时时间，单位为毫秒
	 * @return 函数执行状态
	 * @retval =0 函数执行成功
	 * @retval <0 函数调用失败
	 */
	int  CAN_BL_SetNewBaudRate(int DevHandle,int CANIndex,short NodeAddr,CAN_INIT_CONFIG pInitConfig,int NewBaudRate,int TimeOut);
}
